package com.gukun.springboot.tdengine.service.highvolume;

import com.gukun.springboot.tdengine.pojo.TagInfo;
import com.gukun.springboot.tdengine.domain.enums.TagType;

import java.sql.*;
import java.util.List;

import static com.gukun.springboot.tdengine.service.highvolume.DataUtil.getTagInfos;

/**
 * Prepare target database.
 * Count total records in database periodically so that we can estimate the writing speed.
 */
public class DataBaseMonitor {
    /**
     * 库名称
     */
    public static final String dbname = DataUtil.DBNAME;
    private Connection conn;
    private Statement stmt;

    public DataBaseMonitor init() throws SQLException {
        if (conn == null) {
            String jdbcURL = DataUtil.JDBCURL;
            conn = DriverManager.getConnection(jdbcURL);
            stmt = conn.createStatement();
        }
        return this;
    }

    public void close() {
        try {
            stmt.close();
        } catch (SQLException e) {
        }
        try {
            conn.close();
        } catch (SQLException e) {
        }
    }

    public void prepareDatabase() throws SQLException {
        stmt.execute("DROP DATABASE IF EXISTS " + dbname);
        stmt.execute("CREATE DATABASE " + dbname);
        stmt.execute("CREATE STABLE " + dbname + ".tdouble (ts TIMESTAMP,v double) TAGS (tn VARCHAR(64))");
        stmt.execute("CREATE STABLE " + dbname + ".tfloat (ts TIMESTAMP,v float) TAGS (tn VARCHAR(64))");
        stmt.execute("CREATE STABLE " + dbname + ".tint (ts TIMESTAMP,v integer) TAGS (tn VARCHAR(64))");
        stmt.execute("CREATE STABLE " + dbname + ".tbool (ts TIMESTAMP,v bool) TAGS (tn VARCHAR(64))");

        //新建所有表
        List<TagInfo> tagInfos = getTagInfos(100000);
        try {
            createBatchTable(tagInfos);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public long count() throws SQLException {
        try (ResultSet result = stmt.executeQuery("SELECT count(*) from " + dbname + ".tdouble");
             ResultSet result1 = stmt.executeQuery("SELECT count(*) from " + dbname + ".tfloat");
             ResultSet result2 = stmt.executeQuery("SELECT count(*) from " + dbname + ".tint");
             ResultSet result3 = stmt.executeQuery("SELECT count(*) from " + dbname + ".tbool")) {
            result1.next();
            result2.next();
            result3.next();
            result.next();
            return result.getLong(1)
                    + result1.getLong(1)
                    + result2.getLong(1)
                    + result3.getLong(1);
        }
    }

    public long getTableCount() throws SQLException {
        try (ResultSet result = stmt.executeQuery("select count(*) from information_schema.ins_tables where db_name = '" + dbname + "';")) {
            result.next();
            return result.getLong(1);
        }
    }


    private void createBatchTable(List<TagInfo> tagInfos) throws Exception {
        int batchSize = 5000;
        int group = tagInfos.size() / batchSize;
        for (int i = 0; i < group; i++) {
            StringBuilder sql = new StringBuilder("create table ");
            for (int j = 0; j < batchSize; j++) {
                int index = i * batchSize + j;
                TagInfo tagInfo = tagInfos.get(index);
                String tbName = tagInfo.getTagName();
                String sTableName = getSTableName(tagInfo.getTagType());
                sql.append("if not exists ")
                        .append(dbname).append(".")
                        .append(tbName).append(" using ")
                        .append(sTableName).append(" tags('")
                        .append(tagInfo.getTagName()).append("') ");
//                sql += "if not exists " + dbName + "." + tbName + "(ts timestamp,val "+tagInfo.getTagType()+",quality tinyint)";
            }

            stmt.execute(sql.toString());
        }
    }

    /**
     * 获取超表名称
     *
     * @param type
     * @return
     */
    private String getSTableName(TagType type) {
        String stag = "";
        switch (type) {
            case DOUBLE:
            case BOOL:
            case INT:
            case FLOAT:
                stag = dbname + ".t" + type.name().toLowerCase();
                break;
        }
        return stag;
    }
}